package com.avalon;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URISyntaxException;
import java.util.logging.Logger;
import java.util.logging.Level;

/**
 * 启动类的相关环境变量 
 * 
 * @author mac
 * 
 */
public final class BootEnvironment {
	private static final Logger logger = Logger.getLogger(BootEnvironment.class.getName());

	private BootEnvironment()
	{}

	/**
	 * 相对于{@code   PROJECT_HOME}引导程序的jar的默认位置.
	 */
	public static final String BOOT_JAR = "bin" + File.separator + "boot.jar";

	/**
	 * 属性文件的名称来定位和检索环境属性.
	 */
	public static final String BOOT_PROPERTIES = "boot.properties";

	/**
	 * 表示为 项目的服务器的安装目录.
	 */
	public static final String PROJECT_HOME = "PROJECT_HOME";

	/**
	 * 部署的应用程序应该把jar文件和应用程序的属性文件的目录。
	 */
	public static final String DEPLOY = "DEPLOY";

	/**
	 * 内核属性配置文件.
	 */
	public static final String CONFIG_PROPERTIES = "CONFIG_PROPERTIES";

	/**
	 * 服务器日志.
	 */
	public static final String LOGGING = "LOGGING";

	/**
	 * 日志输出路径.
	 */
	public static final String LOG_OUTPUT = "LOG_OUTPUT";

	/**
	 * 自定义的classpath.
	 */
	public static final String CUSTOM_CLASSPATH_ADD = "CUSTOM_CLASSPATH_ADD";

	/**
	 * JDK的位置启动服务器时使用.
	 */
	public static final String JAVA_HOME = "JAVA_HOME";
	
	/**
	 * JVM命令行参数.
	 */
	public static final String JAVA_OPTS = "JAVA_OPTS";

	/**
	 * 用于JMX连接端口号.
	 */
	public static final String JMX_PORT = "JMX_PORT";

	/**
	 * 是否禁用JMX的安全控制。（默认没有安全检测）
	 */
	public static final String DISABLE_JMX_SECURITY = "DISABLE_JMX_SECURITY";

	/**
	 * 默认的 {@code   DEPLOY} 属性.
	 */
	public static final String DEFAULT_DEPLOY = "${PROJECT_HOME}" + File.separator + "deploy";

	/**
	 * 默认的 {@code   CONFIG_PROPERTIES} 属性.
	 */
	public static final String DEFAULT_PROPERTIES = "${PROJECT_HOME}" + File.separator + "conf" + File.separator
			+ "app.properties";
	/**
	 * 默认的 {@code   CONFIG_PROPERTIES} 属性.
	 */
	public static final String DEFAULT_BOOT_PROPERTIES = "${PROJECT_HOME}" + File.separator + "conf" + File.separator+ "boot.properties";
			
	public static final String DEFAULT_LOG_OUTPUT = "${PROJECT_HOME}" + File.separator + "log" + File.separator
			+ "out.log";
	/**
	 * JMX默认连接端口
	 */
	public static final String DEFAULT_JMX_PORT = "62976";
	/**
	 * JMX默认的安全策略
	 */
	public static final String DEFAULT_DISABLE_JMX_SECURITY = "true";
	/**
	 * 启动的核心类
	 */
	public static final String KERNEL_CLASS = "com.avalon.core.AvalonEngine";

	// "com.zero.engine.core.ALawsEngine";

	/**
	 * 从文件中加载配置属性成SubstitutionProperties对象。如果给定的文件名不为空，它被用作配置文件。否则，
	 * 位于AVA_BOOT资源被用作配置文件。
	 * 
	 * 包含在配置文件中的属性必须符合由SubstitutionProperties允许的规则。
	 * 
	 * 
	 * @param filename
	 *            name of the config file or {@code null} for default
	 * @return a {@code SubstitutionProperties} object representing the
	 *         configuration parameters in the file
	 * @throws IOException
	 *             if there is a problem loading the file
	 * @throws URISyntaxException
	 *             if the filename is invalid
	 */
	public static SubstitutionProperties loadProperties(String filename) throws IOException, URISyntaxException
	{

		// load properties from configuration file
		SubstitutionProperties properties = new SubstitutionProperties();
		URL bootFile = null;
		InputStream is = null;
		try
		{
			if (filename == null)
			{
				bootFile = ClassLoader.getSystemResource(BootEnvironment.BOOT_PROPERTIES);
				if (bootFile==null) {
					bootFile=new File("../conf/"+BootEnvironment.BOOT_PROPERTIES).toURI().toURL();
					System.out.println("没有配置文件路径自行查找,已经找到../conf/boot.properties");
				}
			} else
			{
				bootFile = new File(filename).toURI().toURL();
			}
			is = bootFile.openStream();
			properties.load(is);
		} catch (IOException e)
		{
			logger.log(Level.SEVERE, "Unable to load initial configuration", e);
			throw e;
		} finally
		{
			try
			{
				if (is != null)
				{
					is.close();
				}
			} catch (IOException ignore)
			{
				logger.log(Level.FINEST, "Unable to close stream", ignore);
			}
		}

		// 确定 PROJECT_HOME
		String avaHome = properties.getProperty(BootEnvironment.PROJECT_HOME);
		if (avaHome == null)
		{
			properties.clear();
			URL jarLocation = BootEnvironment.class.getProtectionDomain().getCodeSource().getLocation();

			// 查找文件
			File jarFile = new File(jarLocation.toURI());
			String jarPath = jarFile.getPath();
			int jarFileIndex = jarPath.indexOf(BootEnvironment.BOOT_JAR);
			if (jarFileIndex == -1)
			{
				logger.log(Level.SEVERE, "Unable to determine PROJECT_HOME");
				throw new IllegalStateException("Unable to determine PROJECT_HOME");
			} else
			{
				avaHome = jarPath.substring(0, jarFileIndex - 1);
				properties.setProperty(BootEnvironment.PROJECT_HOME, avaHome);
				// 重载的属性，以便为AVA_HOME值在任何其他变量正确写入
				is = null;
				try
				{
					is = bootFile.openStream();
					properties.load(is);
				} catch (IOException e)
				{
					logger.log(Level.SEVERE, "Unable to load initial configuration", e);
					throw e;
				} finally
				{
					try
					{
						if (is != null)
						{
							is.close();
						}
					} catch (IOException ignore)
					{
						logger.log(Level.FINEST, "Unable to close stream", ignore);
					}
				}
			}
		}
		logger.log(Level.CONFIG, "  PROJECT_HOME = " + avaHome);

		// 加载默认设置缺少的属性
		configureDefaultProperties(properties);

		return properties;
	}

	/**
	 * 加载默认值给定的属性如有需要的属性丢失。
	 * 
	 * @param properties
	 *            the set of boot configuration properties
	 */
	private static void configureDefaultProperties(SubstitutionProperties properties)
	{

		// load defaults for any missing properties
		if (properties.getProperty(BootEnvironment.BOOT_PROPERTIES) == null)
		{
			properties.setProperty(BootEnvironment.BOOT_PROPERTIES, BootEnvironment.DEFAULT_BOOT_PROPERTIES);
		}
		if (properties.getProperty(BootEnvironment.LOG_OUTPUT) == null)
		{
			properties.setProperty(BootEnvironment.LOG_OUTPUT, BootEnvironment.DEFAULT_LOG_OUTPUT);
		}
		if (properties.getProperty(BootEnvironment.DEPLOY) == null)
		{
			properties.setProperty(BootEnvironment.DEPLOY, BootEnvironment.DEFAULT_DEPLOY);
		}
		if (properties.getProperty(BootEnvironment.CONFIG_PROPERTIES) == null)
		{
			properties.setProperty(BootEnvironment.CONFIG_PROPERTIES, BootEnvironment.DEFAULT_PROPERTIES);
		}
		if (properties.getProperty(BootEnvironment.JMX_PORT) == null)
		{
			properties.setProperty(BootEnvironment.JMX_PORT, BootEnvironment.DEFAULT_JMX_PORT);
		}
		if (properties.getProperty(BootEnvironment.DISABLE_JMX_SECURITY) == null)
		{
			properties.setProperty(BootEnvironment.DISABLE_JMX_SECURITY, BootEnvironment.DEFAULT_DISABLE_JMX_SECURITY);
		}

		// configure JAVA_HOME automatically if necessary
		if (properties.getProperty(BootEnvironment.JAVA_HOME) == null)
		{
			properties.setProperty(BootEnvironment.JAVA_HOME, System.getProperty("java.home"));
		}
		
	}

}
